<?php
/**
 * 文件上传类
 *
 * @author Mo yi <root@imoi.cn>
 * @link   http://www.imoi.cn
 * @copyright Copyright &copy; 2010-2012 DuoLam Software LLC
 * @license http://www.imoi.cn/license/
 * @version $Id: dpUpload.php 1 2012-04-04 13:35:54Z Mo.yi $
 * @package web.helper
 * @since 1.0
 */

class dpUpload
{

	/**
	 * 配置信息
	 */
	private $_config = array();

	/**
	 * mime文件类型列表
	 */
	private $_mime = array();

	/**
	 * 允许上传文件列表
	 */
	private $_type;

	/**
	 * 上传目录
	 */
	private $_dir;

	/**
	 * 附件目录里的子目录
	 */
	private $_child;

	/**
	 * 附件总目录
	 */
	private $_attachment;

	/**
	 * 单文件允许上传的大小
	 */
	private $_size;

	/**
	 * 当前上传的文件
	 */
	private $_file;

	/**
	 * 构造方法，设置单文件允许上传的大小，和允许上传的类型
	 * @param int $size 单文件最大上传大小，单位：兆
	 * @param string $type 允许上传的类型
	 * @param string $dir 上传目录地址
	 */
	public function __construct($config = array())
	{
		$this->_size = empty($config['size']) ? 1 * 1024 * 1024 : (int)($config['size'] * 1024 * 1024);
		$this->_type = empty($config['type']) ? 'jpg,gif,png' : $config['type'];
		$mime = D::import('system:web.util.mimeTypes',true);
		$type = explode(',', $this->_type);
		$this->_child = empty($config['child']) ? date('Ym') : $config['child'];
		$this->_attachment = empty($config['attach']) ? 'attachment' : $config['attach'];
		$this->_config['app_path'] = !empty($config['app_path']) ? $config['app_path'] : APP_PATH;
		$this->_config = array_merge($config, $this->_config);
		foreach ($type as $v) if (isset($mime[$v])) $this->_mime[] = $mime[$v];
		$this->_checkDir();
	}

	/**
	 * 设置允许上传的类型
	 * @param string $type 上传类型，以逗号分开每种类型
	 * @return object $this 返回类本身
	 */
	public function setType($type)
	{
		$this->_type = $type;
		return $this;
	}

	/**
	 * 获取允许上传类
	 * @return string
	 */
	public function getType()
	{
		return $This->_type;
	}

	/**
	 * 设置单文件上传的大小，单位：兆
	 * @param int $size 允许的文件大小
	 * @return object $this 返回类本身
	 */
	public function setSize($size)
	{
		$this->_size = (int)$size * 1024 * 1024;
		return $this;
	}

	/**
	 * 获取单文件允许上传的大小
	 * @return int 单位：兆
	 */
	public function getSize($is = true)
	{
		return $is ? $this->_size / 1024 / 1024 : $this->_size;
	}

	/**
	 * 运行，保存上传文件
	 * @param string input表单的name属性值
	 * @return array 上传后的文件信息，包括原文件名、新文件名。
	 */
	public function save($name)
	{
		if (isset($_FILES[$name])) {
			if (is_array($_FILES[$name]['name'])) {
				foreach ($_FILES[$name]['name'] as $f_key => $f_value) {
					$file['name']     = $_FILES[$name]['name'][$f_key];
					$file['type']     = $_FILES[$name]['type'][$f_key];
					$file['size']     = $_FILES[$name]['size'][$f_key];
					$file['error']    = $_FILES[$name]['error'][$f_key];
					$file['tmp_name'] = $_FILES[$name]['tmp_name'][$f_key];
					$info = $this->_upload($file);
					if (is_array($info)) {
						$infos[] = $info;
					} else {
						$infos[$f_key]['error']    = $info;
						$infos[$f_key]['name']     = null;
						$infos[$f_key]['new_name'] = null;
					}
				}
				return $infos;
			}
			else
				return $this->_upload($_FILES[$name]);
		}
	}

	/**
	 * 上传一个文件
	 * @param array $file $_FILES 数组
	 * @return array || string 上传后的信息
	 */
	private function _upload($file)
	{
		$this->_file = &$file;
		if ($this->_file['error'] > 0)
			return $this->_getError($this->_file['error']);
		else {
			$type = explode(',', $this->_type);

			if ($this->_file['size'] > $this->getSize(false))
				return $this->_getError('10');
			
			if (isset($_config['check_type']) && $_config['check_type'] == true) {
				if (!in_array($this->_file['type'], $this->_mime))
					return $this->_getError('11');
			}

			if (!in_array($this->_getFileSuffix($this->_file['name']), $type))
				return $this->_getError('12');

			$newName = $this->_getName($this->_file['name']);
			@move_uploaded_file($this->_file['tmp_name'], $newName);
			return array(
				'name'     => $this->_file['name'],
				'new_name' => str_replace('\\','/',substr($newName, strlen($this->_config['app_path']))),
				'error'    => null,
			);
		}
	}

	/**
	 * 获取文件名后缀
	 * @param string 要上传的文件名
	 * @return string 文件扩展名
	 */
	private function _getFileSuffix($name)
	{
		return substr(strrchr($name, '.'),1);
	}

	/** 
	 * 获取上传后的新文件名
	 * @param string 要上传的文件名
	 * @return string 新文件名
	 */
	private function _getName($name)
	{
		return $this->_dir . md5((time() - rand()) .'_'.md5(date('YmdHis'))) . strrchr($name,'.');
	}

	/**
	 * 获取上传错误信息
	 * @param int 错误代码
	 * @return string 错误信息
	 */
	private function _getError($code)
	{
		$error = array(
			'1'  => '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。',
			'2'  => '上传文件的大小超过了 html 表单中 max_file_size 选项指定的值。',
			'3'  => '文件只有部分被上传。',
			'4'  => '没有文件可以上传。',
			'5'  => '找不到临时文件夹。',
			'6'  => '文件写入失败。',

			'10' => '上传文件的大小超过系统设置的大小',
			'11' => '上传的文件mime类型不被允许',
			'12' => '上传的文件类型不被允许',
		);
		return $error[$code];
	}

	/** 
	 * 检测上传文件目录
	 */
	private function _checkDir()
	{
		if (empty($this->_config['attach']))
			$this->_dir  = APP_PATH . DS . $this->_attachment . DS;
		else
			$this->_dir = $this->_attachment;
		is_dir($this->_dir) or @mkdir($this->_dir, 0777, true);
		$this->_dir .= $this->_child . DS;
		is_dir($this->_dir) or @mkdir($this->_dir, 0777, true);
	}

}
?>